package qc.module.cms.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.module.cms.dto.link.LinkDto;
import qc.module.cms.entity.Link;
import qc.module.cms.entity.LinkCategory;
import qc.module.cms.mapper.LinkMapper;
import qc.module.cms.repository.LinkCategoryRepository;
import qc.module.cms.repository.LinkRepository;

import java.util.List;

/**
 * LinkService
 *
 * @author QuCheng Tech
 * @since 2023/5/25
 */
@Service
public class LinkService {
    private LinkRepository repository;

    @Autowired
    public void setLinkRepository(LinkRepository repository) {
        this.repository = repository;
    }

    private LinkCategoryRepository categoryRepository;

    @Autowired
    public void setLinkCategoryRepository(LinkCategoryRepository categoryRepository) {
        this.categoryRepository = categoryRepository;
    }

    /**
     * 获取指定分类下的链接集合，可传参指定是否包含无效（禁用或已删除）分类
     *
     * @param categoryId     分类ID
     * @param includeInvalid 是否包含无效分类
     * @return 分类集合
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    public List<LinkDto> getCategoryLinks(Integer categoryId, boolean includeInvalid) throws QCPromptException {
        if (categoryId == null)
            throw new QCPromptException("分类ID不能为空");

        LambdaQueryWrapper<Link> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Link::getCid, categoryId);
        if (!includeInvalid) {
            //不包含无效链接分类，过滤查询条件
            wrapper.eq(Link::getFlag, ResourceStatusFlagEnum.NORMAL);
        }
        //排序
        wrapper.orderByAsc(Link::getOdr);

        //查询数据
        List<Link> list = repository.selectList(wrapper);
        if (list != null && list.size() > 0x0) {
            //转换类型
            return LinkMapper.MAPPER.toDtoList(list);
        }

        return null;
    }

    /**
     * 获取指定ID的链接信息
     *
     * @param id 链接ID
     * @return 链接信息
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    public LinkDto get(Integer id) throws QCPromptException {
        if (id == null)
            throw new QCPromptException("链接ID不能为空");

        Link link = repository.selectById(id);

        if (link != null)
            return LinkMapper.MAPPER.toDto(link);

        return null;
    }

    /**
     * 新增分类
     *
     * @param dto 分类信息
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    public String add(LinkDto dto) {
        if (dto == null)
            return QCUnifyReturnValue.Warn("对象不能为空");
        if (StringUtils.isBlank(dto.getName()))
            return QCUnifyReturnValue.Warn("链接名称不能为空");
        if (StringUtils.isBlank(dto.getUrl()))
            return QCUnifyReturnValue.Warn("链接地址不能为空");
        if (dto.getCid() < 0x1)
            return QCUnifyReturnValue.Warn("链接分类ID不能为空");
        //判断分类是否存在
        if (!hasCategoryIdExist(dto.getCid()))
            return QCUnifyReturnValue.Warn("链接分类ID不存在");
        //判断名称不能重复
        if (isNameHasExist(dto.getName(), 0x0))
            return QCUnifyReturnValue.Warn("链接名称已存在，名称不能相同");

        //DTO转换为Entity
        Link en = LinkMapper.MAPPER.LinkDtoToEntity(dto);

        //2023-5-25，实测设置数据库中自增和在实体类中设置自增ID均无法使用
        //修改为使用代码赋值，获取数据库中的最大id+1后赋值
        en.setId(genereateId());

        if (repository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("保存失败");

        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改分类
     *
     * @param dto 分类信息
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    public String update(LinkDto dto) {
        if (dto == null)
            return QCUnifyReturnValue.Warn("对象不能为空");
        if (dto.getId() < 0x1)
            return QCUnifyReturnValue.Warn("链接ID不能为空");
        if (StringUtils.isBlank(dto.getName()))
            return QCUnifyReturnValue.Warn("链接名称不能为空");
        if (StringUtils.isBlank(dto.getUrl()))
            return QCUnifyReturnValue.Warn("链接地址不能为空");
        if (dto.getCid() < 0x1)
            return QCUnifyReturnValue.Warn("链接分类ID不能为空");
        //判断分类是否存在
        if (!hasCategoryIdExist(dto.getCid()))
            return QCUnifyReturnValue.Warn("链接分类ID不存在");

        //DTO转换为Entity
        Link en = LinkMapper.MAPPER.LinkDtoToEntity(dto);

        //判断名称不能重复
        if (isNameHasExist(en.getName(), en.getId()))
            return QCUnifyReturnValue.Warn("链接名称已存在，名称不能相同");

        repository.updateById(en);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 判断指定的分类ID是否存在
     *
     * @param categoryId 分类ID
     * @return true表示已存在，false表示不存在
     * @author QuCheng Tech
     * @since 2023/5/26
     */
    public boolean hasCategoryIdExist(Integer categoryId) {
        LambdaQueryWrapper<LinkCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LinkCategory::getId, categoryId);

        LinkCategory en = categoryRepository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * 删除，通过传参指定是物理删除还是修改标记
     *
     * @param id            分类ID
     * @param isLogicDelete 是否为逻辑删除，为true时对记录标记进行修改
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    public String delete(Integer id, boolean isLogicDelete) {
        if (id == null)
            return QCUnifyReturnValue.Warn("要删除的对象ID不能为空");

        if (!hasIdExist(id))
            return QCUnifyReturnValue.Warn("要删除的链接不存在");

        if (isLogicDelete) {
            //逻辑删除，修改状态标记，不删除记录
            LambdaUpdateWrapper<Link> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Link::getId, id);

            wrapper.set(Link::getFlag, ResourceStatusFlagEnum.DELETED);

            repository.update(null, wrapper);
        } else {
            repository.deleteById(id);
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 物理删除指定分类下的所有链接
     *
     * @param categoryId 分类ID
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    public String deleteCategoryLinks(Integer categoryId) {
        if (categoryId == null)
            return QCUnifyReturnValue.Warn("要删除的分类ID不能为空");

        LambdaUpdateWrapper<Link> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Link::getCid, categoryId);

        repository.delete(wrapper);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 判断指定的ID是否存在
     *
     * @param id 链接ID
     * @return true表示已存在，false表示不存在
     * @author QuCheng Tech
     * @since 2023/5/26
     */
    public boolean hasIdExist(Integer id) {
        LambdaQueryWrapper<Link> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Link::getId, id);

        Link en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * @param name 名称
     * @param id   ID，新增时设置ID为0，修改时设置ID为记录ID
     * @return true表示名称已存在，false表示名称不存在
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    boolean isNameHasExist(String name, Integer id) {
        //验证名称是否重复条件：name=name and id<>id
        LambdaQueryWrapper<Link> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Link::getName, name);
        wrapper.ne(Link::getId, id);

        Link en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * 生成记录ID，获取数据库表中的最大记录ID+1
     *
     * @return 生成记录ID
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer genereateId() {
        Integer maxRecordId = getMaxId();
        return maxRecordId + 1;
    }

    /**
     * 获取数据库表中的最大ID值，没有记录时返回0
     *
     * @return 返回数据库表中的最大ID值
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer getMaxId() {
        LambdaQueryWrapper<Link> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Link::getId);
        wrapper.orderByDesc(Link::getId);
        Link en = repository.selectOne(wrapper);
        if (en != null)
            return en.getId();

        return 0x0;
    }
}